package com.pace.ribbon.aop;

import com.pace.ribbon.annotation.LoveForest;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.StringUtils;
import java.lang.reflect.Method;

@Aspect
@Configuration
public class MyAop {


    //定义切点方法
    @Pointcut("@annotation(com.pace.ribbon.annotation.LoveForest)")
    public void pointCut() {
    }

//    @Before("pointCut()")
    public void beforeMethod(JoinPoint joinPoint) {
        System.out.println("before method   start ..."+joinPoint.toString());

        System.out.println("before method   end ...");
    }



    /**
     * 环绕通知 around advice
     * 这个切的是 com.pace.service 包下面以及子包下所有，后面又 && 同时满足带有注解 loveForest
     */
    @Around(value = "pointCut() && @annotation(loveForest)", argNames = "joinPoint, loveForest")
    public Object methodAround(ProceedingJoinPoint joinPoint, LoveForest loveForest) throws Throwable {
        System.out.println("Around method    start.......................");
        //获得自定义注解的参数
        System.out.println("Around method  methodLog 的参数，remark：" + loveForest.value() + " key：" + loveForest.key());
        //执行目标方法，并获得对应方法的返回值
        Object result = joinPoint.proceed();
        System.out.println("Around method     返回结果：" + result);
        System.out.println("Around method          end.......................");
        return result;
    }


    /**
     * 最终通知 after advice
     * 使用的是在上面声明的切面，并且带上个注解，意思是除了满足上面pointCut()方法的条件还得带上注解才OK
     */
//    @After(value = "pointCut() && @annotation(loveForest)", argNames = "joinPoint, loveForest")
    public void methodAfter(JoinPoint joinPoint, LoveForest loveForest) throws Throwable {
        System.out.println("After method     start.......................");
        //获得自定义注解的参数
        System.out.println("After method   methodLog 的参数，remark：" + loveForest.value() + " key：" + loveForest.key());
        LoveForest remark = getMethodRemark(joinPoint);
        System.out.println("After method        end......................."+remark);
    }

    /**
     * 获取方法的中文备注____用于记录用户的操作日志描述
     */
    private LoveForest getMethodRemark(JoinPoint joinPoint) throws Exception {
        //返回目标对象
        Object target = joinPoint.getTarget();
        String targetName = target.getClass().getName();
        //返回当前连接点签名
        String methodName = joinPoint.getSignature().getName();
        //获得参数列表
        Object[] arguments = joinPoint.getArgs();

        Class targetClass = Class.forName(targetName);
        Method[] method = targetClass.getMethods();
        for (Method m : method) {
            if (m.getName().equals(methodName)) {
                Class[] tmpCs = m.getParameterTypes();
                if (tmpCs.length == arguments.length) {
                    LoveForest methodCache = m.getAnnotation(LoveForest.class);
                    if (methodCache != null && !StringUtils.isEmpty(methodCache)) {
                        return methodCache;
                    }
                    break;
                }
            }
        }
        return null;
    }


    /**
     * 后置异常通知
     */
//    @AfterThrowing("pointCut()")
    public void afterThrows(JoinPoint jp){
        System.out.println("方法异常时执行.....");
    }


}
